package cn.xiaolang.thread.juc;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

/**
 * 分而治之，就是说当一个任务非常大的时候，我们可以按照一定的业务需求拆分为若干个小的任务，
 * 最后把这些小的任务再聚合起来
 *
 * @author fuhw/Dean
 * @date 2020-03-05
 */
public class ForkJoinStarted {

    public static void main(String[] args) {
        int dataSize = 101;
        // 定义数组
        int[] arr = new int[dataSize];
        for (int i = 0; i < dataSize; i++) {
            arr[i] = i + 1;
        }
        ForkJoinPool pool = new ForkJoinPool();
        SumTask innerFind = new SumTask(arr, 0, arr.length - 1);
        pool.invoke(innerFind);
        pool.shutdown();
        System.out.println("完成,结果是:" + innerFind.join());
    }

    /**
     * 注意：
     * <p>
     * 1.如果有返回值就继承RecursiveTask，没有返回值就继承RecursiveAction
     * <p>
     * 2.上面是同步调用，如果想要异步调用，可以使用pool.execute(...);替换上面的invoke方法
     */
    static class SumTask extends RecursiveTask<Integer> {

        /**
         * 阀值，当数组长度小于10就不再拆分
         */
        private static final int THRESHOLD = 10;
        private final int[] dataArr;
        private final int start;
        private final int end;

        SumTask(int[] dataArr, int start, int end) {
            this.dataArr = dataArr;
            this.start = start;
            this.end = end;
        }

        @Override
        protected Integer compute() {
            // 存储结果
            int sum = 0;
            // 存储任务
            List<SumTask> tasks = new ArrayList<>();

            if (end - start > THRESHOLD) {
                // 使用异步的方式拆分一个任务去执行
                int mid = (start + end) / 2;
                SumTask leftTask = new SumTask(dataArr, start, mid);
                SumTask rightTask = new SumTask(dataArr, mid + 1, end);
                leftTask.fork();
                rightTask.fork();
                tasks.add(leftTask);
                tasks.add(rightTask);
            } else {
                for (int j = start; j <= end; j++) {
                    sum = sum + dataArr[j];
                }
                return sum;
            }

            for (SumTask task : tasks) {
                sum = sum + task.join();
            }
            return sum;
        }
    }

}

